#include <iostream>
#include <fstream>

#include <string>
#include <unordered_map>
#include <unordered_set>

#include <regex>

using namespace std;

using line_t = unsigned long long;

// *****************************************************************************************************
constexpr char KEY_KIND = 'k';		// 关键字
constexpr char ID_KIND = 'i';		// 标识符
constexpr char UINT_KIND = 'u';		// 非负整数
constexpr char DCHAR_KIND = 'd';        // 双分界符
constexpr char NULL_KIND = '`';		// 空 类型
const unordered_map<char, string> Kind_Str{ {KEY_KIND, "key"}, {ID_KIND, "ID"}, {UINT_KIND, "Uint"}, {DCHAR_KIND, "dchar"}};

const unordered_set<string> Keys{ "if", "else", "while", "for", "int" };
const unordered_set<string> Dchars{ ">=", "<=", "==", "!=" };     
const unordered_set<char> Dchars_Sta{ '>', '<', '=', '!' };     // 双分界符的第一个字符 
const unordered_set<char> Singles{ '+', '-', '*', '/', '=', '{', '}', '(', ')', 
    '<', '>', ';', '!', ',' }; 

const string WARN_STR = "~~ ";   

// ******************************************************************************************************

template <typename T>
std::string mark(const T& t, const string c = "\"")
{
    return " " + c + std::string{t} + c + " ";
} 

bool is_dchar(const string& s)
{
    return Dchars.count(s);
}

bool is_identifier(const string& temp)
{
    string pattern = "^[a-zA-Z_](?:[a-zA-Z0-9_]+)*";
    regex reg(pattern);
    return (regex_match(temp, reg));
}

bool is_uint(const string& s)
{
    for (char c : s) 
        if (!isdigit(c)) return false;
    return true;
}

char ret_kind(const string& s) 
{
    if (Keys.count(s)) return KEY_KIND;
    if (is_identifier(s)) return ID_KIND;
    if (is_uint(s)) return UINT_KIND;
    if (is_dchar(s)) return DCHAR_KIND;   
    return NULL_KIND;
}

bool is_id_ch(char c)
{
    return c == '_' || isalnum(c);
}

bool is_dchar_sta(char c)
{
    return Dchars_Sta.count(c);
}

// ********************** ID *****************************
class Identifier {
public:
	Identifier() :_val{ } { }	// _val = "" ->  "空标识符"
	Identifier(const string& s) :_val{ s }
    {
        if (!is_identifier(s)) throw string{ mark(s) + "isn't a legal id"};
    }

	string str() const
    {
        if (this->empty()) throw string{ WARN_STR + "ID is empty"};     // ! 避免误用
        return _val;
    }

	bool empty() const { return _val.empty(); }

private:
	std::string _val;
};

istream& operator>>(istream& is, Identifier& n)
{
    char c = '0';
    is >> c;
    if (c != '_' && !isalpha(c)) {
        if (!is.eof()) is.putback(c);
		n = Identifier{};
		return is;
	}
	string s{c};
	while (!isspace(is.peek()) && is >> c) {
		if (!is_id_ch(c)) {	
			is.putback(c);		// ********
			break;
		}
		s += c;
	}
	n = Identifier{ s };
	return is;
}

// *********************** Uint ****************************
class Uint {
public:
    Uint() :_val{ } { }
    Uint(const string& n) :_val{ n } 
    {
        if (!is_uint(n)) throw string{ mark(n) + "isn't a legal Uint"};
    } 

    bool empty() const { return _val.empty(); }
    string str() const 
    { 
        if (this->empty()) throw string{WARN_STR + "Uint is empty"};       // ! 避免误用
        return _val; }

private:
    string _val;
};

istream& operator>>(istream& is, Uint& u)
{
    char c = ' ';
    is >> c;
    if (!isdigit(c)) {		// 如果不判断，当输入为负数时，也会正常读取
        if (!is.eof()) is.putback(c);
        u = Uint{};
        return is;
    }
    string s{c};
    while (!isspace(is.peek()) && is >> c) {
        if (!isdigit(c)) {
            is.putback(c);
            break;
        }
        s += c;
    }
    u = Uint{ s };
    return is;
}


// ********************** Lexer **************************
struct Lexer {
	char kind;
	string val;
	
	Lexer() :kind{ NULL_KIND }, val{} { };		// NULL_Lexer: <NULL_KIND, ""> 
	Lexer(char c) :kind{ c }, val{ c }
    {
        if (!Singles.count(c)) throw string(mark(c) + "isn't a legal single char");
    }

	Lexer(const string& s) :kind{ ret_kind(s) }, val{ s }
    {
        if (kind == NULL_KIND) throw string{mark(s) + "isn't a legal lexer"};
    }
	// Lexer(char kind, const string& s);
	
	bool empty() const { return kind == NULL_KIND && val.empty(); }
};


// ************************* Lex *****************************
class Lex {
public:
	Lex(istream& is) :_is{ is }, _line{ 1 } { }
	
	Lexer get();
    line_t line() const { return _line; }

private:
	istream& _is;
    line_t _line;       // 记录当前行数

    void _ignore_annotation(bool is_line = true);        // 忽略注释，默认行注释
    void _update_line();        // 更新行数
};

Lexer Lex::get()
{
    _update_line();
    
    Identifier id;
    _is >> id;      // * 1. id or key
    if (!id.empty()) return Lexer{ id.str() };  
    if (_is.eof()) return Lexer{};      // ** 注意所在位置

    Uint u;     
    _is >> u;       // * 2. Uint
    if (!u.empty()) return Lexer{ u.str() };

    char c = NULL_KIND;
    _is >> c;
    if (is_dchar_sta(c)) {    
        if (_is.peek() == '=') {      // * 3. 双分界符 
            _is.get();      // ** 记得把 '=' 读取了
            return Lexer{ string{c} + "=" };
        }
    }
    // *********** 注释 **************
    else if (c == '/' && (_is.peek() == '/' || _is.peek() == '*')) {
        if (_is.peek() == '/') _ignore_annotation();
        else _ignore_annotation(false);
        return this->get();
    }
    // ******************************
    return Lexer{ c };      // * 4. 单分界符
}

void Lex::_ignore_annotation(bool is_line)
{
    _is.get();      // **** 避免 bug:  '/*/'
    if (is_line) {		// 行注释
        string s;
        getline(_is, s);
        _line++;        // * 别忘了更新行数
    }
    else {		 // 块注释
        char c;
        while (true) {
            _is >> noskipws >> c;
            if (c == '\n') _line++;     // * 别忘了更新行数
            if (_is.eof()) throw string("lack of" + mark("*/"));        // !!
            if (c == '*' && _is.peek() == '/') {
                _is.get();
                return;
            }
            else if (c == '/' && _is.peek() == '*')     // ! 注释嵌套
                throw string("annotation nest");
        }
    }
}

void Lex::_update_line()
{
    while (true) {	
        char c;
        _is >> noskipws >> c;		// 避免跳过空行
        if (_is.eof()) return;
        if (c == '\n') _line++;
        if (!isspace(c)) {
            _is.putback(c);
            break;
        }
    }
}


// *************************** main *********************************  
void prompt()
{
    cout << "input by line;" << endl;
    cout << "when the input path is not exist, the pragram end running" << endl;
}

string input()        // 输入文件路径 
{
    string s;
    cout << "enter file-path: ";
    getline(cin, s);
    return s;
}

 
void imitate()
{
    line_t line = 1;
    while (true) 
    try{
        string path = input();
        ifstream ifs{ path };
        if (!ifs) return;
        Lex lex{ ifs };
        while (true) {
            Lexer lexer = lex.get();
            line = lex.line();
            if (lexer.empty()) break;      // 文件读取结束
            string kind = (Kind_Str.count(lexer.kind)) ? Kind_Str.at(lexer.kind) : lexer.val;
            cout << "<" << kind << ", " << lexer.val << ">" << endl;
        }
        cout << endl;
    }
    catch(string& e)
    {
        cerr << "line " << line << ": " + e << endl;
    }
}

int main()
try{
    prompt();
    imitate();
    return 0;
}
catch(string& e)
{
    cerr << e << endl;
    return 1;
}